package titan.wizards.newTitanProject;

import java.io.File;
import java.util.TimeZone;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import titan.messages.Messages;
import titan.utils.FileUtils;
import titan.utils.SWTUtils;
import titan.utils.TextValidator;
import titan.utils.TitanUtils;
import titan.wizards.BaseTitanPage;

/**
 * At this page the user can define: name, description, login url and application access url,
 * application responsible e-mail, time zone, supported languages, cache path and application logo.
 * It's possible to enable: debug mode, chat use, all the section (by default), and only firefox mode
 */
public class ProjectPage extends BaseTitanPage {
	Text name;
	Text description;
	Text url;
	Text email;
	Text loginUrl;
	Text cacheDir;
	Text logoPath;
	List usedLang;
	List notUsedLang;
	Button section;
	Button chat;
	Button debug;
	Button firefox;
	Combo timeZoneCombo;
	//Internal data
	boolean active;
	private boolean isDialogOpen;
	private Button cacheDirButton;
	private Button logoButton;
	//Status
	IStatus nameStatus;
	IStatus urlStatus;
	IStatus emailStatus;
	IStatus loginUrlStatus;
	IStatus cacheDirStatus;
	IStatus logoPathStatus;

	// These filter extensions are used to filter which files are displayed.
	private static final String[] FILTER_NAMES = { Messages.ImageFiles + " (png, jpg, bmp)" }; //$NON-NLS-1$
	private static final String[] FILTER_EXTS = { "*.png;*.jpg;*.bmp" }; //$NON-NLS-1$

	protected ProjectPage() {
		super(Messages.ProjectConfiguration);
		setTitle(Messages.ProjectConfiguration);
		setDescription(Messages.ProjectPage_desc);
		active = false;
		isDialogOpen = false;
		IStatus status = new Status(IStatus.OK, "default", ""); //$NON-NLS-1$ //$NON-NLS-2$
		nameStatus = urlStatus = emailStatus = loginUrlStatus = cacheDirStatus = logoPathStatus = status;
	}

	/**
	 * {@inheritDoc}
	 */
	public void createControl(Composite parent) {
		Composite composite = new Composite(parent, SWT.NONE);
		int max = 6;
		GridLayout layout = new GridLayout(max, false);
		layout.verticalSpacing = 10;
		composite.setLayout(layout);
		setControl(composite);
		GridData gd = new GridData(350, 13);

		MouseTrackAdapter mouseExit = new MouseTrackAdapter() {
			public void mouseExit(MouseEvent e) {
			    applyStatus(pageStatus);
			}
		};

		new Label(composite, SWT.NONE).setText(Messages.InstanceName+":"); //$NON-NLS-1$
		name = new Text(composite, SWT.BORDER | SWT.SINGLE);
		gd.horizontalAlignment = SWT.FILL;
		gd.horizontalSpan = max-1;
		name.setLayoutData(gd);
		name.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent event) {
				Status status = new Status(IStatus.OK, "name", ""); //$NON-NLS-1$ //$NON-NLS-2$
				if(!name.getText().isEmpty()) { //$NON-NLS-1$
					if(!TextValidator.isValidSpacedUAlnum(name.getText())){
						status = new Status(IStatus.ERROR, "name", //$NON-NLS-1$
								Messages.InvalidValue+Messages.Name_ext);
					} else {
						if(status.getSeverity() != IStatus.ERROR && TitanUtils.existEclipseProject(name.getText()))
							status = new Status(IStatus.WARNING, "name", Messages.EclipseProjTaken); //$NON-NLS-1$
					}
				}
				applyStatus(status);
				if(active)
					updateButtons();
				else
					active = true;
			}
		});
		name.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "name", Messages.Name_desc) ); //$NON-NLS-1$
			}
		});
		name.addMouseTrackListener(mouseExit);

		new Label(composite, SWT.NONE).setText(Messages.Description+":"); //$NON-NLS-1$
		description = new Text(composite, SWT.BORDER | SWT.SINGLE);
		gd = new GridData();
		gd.horizontalSpan = max-1;
		gd.horizontalAlignment = SWT.FILL;
		description.setLayoutData(gd);
		description.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent event) {
				Status status = new Status(IStatus.OK, "description", ""); //$NON-NLS-1$ //$NON-NLS-2$
				if(!description.getText().isEmpty()) { //$NON-NLS-1$
					if(!TextValidator.isValidUSentence(description.getText()))
						status = new Status(IStatus.ERROR, "description", //$NON-NLS-1$
								Messages.InvalidValue+Messages.Description_ext);
				}
				applyStatus(status);
				updateButtons();
			}
		});
		description.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "description", Messages.Description_desc) ); //$NON-NLS-1$
			}
		});
		description.addMouseTrackListener(mouseExit);

		new Label(composite, SWT.NONE).setText(Messages.Url+":"); //$NON-NLS-1$
		url = new Text(composite, SWT.BORDER | SWT.SINGLE);
		gd = new GridData();
		gd.horizontalSpan = max-1;
		gd.horizontalAlignment = SWT.FILL;
		url.setLayoutData(gd);
		url.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent event) {
				String newUrl = url.getText();
				Status status = new Status(IStatus.OK, "url", ""); //$NON-NLS-1$ //$NON-NLS-2$
				if(!newUrl.isEmpty() && newUrl.compareTo("http://") != 0) { //$NON-NLS-1$ //$NON-NLS-2$
					if(!TextValidator.isValidUrl(newUrl)){
						status = new Status(IStatus.ERROR, "url", //$NON-NLS-1$
								Messages.InvalidValue+Messages.Url_ext);
						loginUrl.setText(""); //$NON-NLS-1$
					} else {
						if(!newUrl.endsWith("/")) //$NON-NLS-1$
							newUrl += "/"; //$NON-NLS-1$
			            loginUrl.setText(newUrl+"titan.php?target=login"); //$NON-NLS-1$
					}
				} else
					loginUrl.setText(""); //$NON-NLS-1$
				applyStatus(status);
				updateButtons();
			}
		});
		url.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "url",  //$NON-NLS-1$
			    		Messages.Url_desc) );
			}
		});
		url.addMouseTrackListener(mouseExit);

		new Label(composite, SWT.NONE).setText(Messages.Email+":"); //$NON-NLS-1$
		email = new Text(composite, SWT.BORDER | SWT.SINGLE);
		gd = new GridData();
		gd.horizontalSpan = max-1;
		gd.horizontalAlignment = SWT.FILL;
		email.setLayoutData(gd);
		email.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent event) {
				Status status = new Status(IStatus.OK, "email", ""); //$NON-NLS-1$ //$NON-NLS-2$
				if(!email.getText().isEmpty()) { //$NON-NLS-1$
					if(!TextValidator.isValidEmail(email.getText()))
						status = new Status(IStatus.ERROR, "email", //$NON-NLS-1$
								Messages.InvalidValue+"e-mail"); //$NON-NLS-1$
				}
				applyStatus(status);
				updateButtons();
			}
		});
		email.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "email",  //$NON-NLS-1$
							Messages.Email_desc) );
			}
		});
		email.addMouseTrackListener(mouseExit);

		new Label(composite, SWT.NONE).setText(Messages.LoginUrl+":"); //$NON-NLS-1$
		loginUrl = new Text(composite, SWT.BORDER | SWT.SINGLE);
		gd = new GridData();
		gd.horizontalSpan = max-1;
		gd.horizontalAlignment = SWT.FILL;
		loginUrl.setLayoutData(gd);
		loginUrl.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent event) {
				Status status = new Status(IStatus.OK, "loginUrl", ""); //$NON-NLS-1$ //$NON-NLS-2$
				if(!loginUrl.getText().isEmpty()) { //$NON-NLS-1$
					if(!TextValidator.isValidFullUrl(loginUrl.getText()))
						status = new Status(IStatus.ERROR, "loginUrl", //$NON-NLS-1$
								Messages.InvalidValue+Messages.LoginUrl_ext);
				}
				applyStatus(status);
				updateButtons();
			}
		});
		loginUrl.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "loginUrl",  //$NON-NLS-1$
							Messages.LoginUrl_desc) );
			}
		});
		loginUrl.addMouseTrackListener(mouseExit);

		new Label(composite, SWT.NONE).setText(Messages.CachePath+":"); //$NON-NLS-1$
		cacheDir = new Text(composite, SWT.BORDER | SWT.SINGLE);
		gd = new GridData();
		gd.horizontalSpan = max-2;
		gd.horizontalAlignment = SWT.FILL;
		cacheDir.setLayoutData(gd);
		cacheDir.addListener(SWT.MouseDown, new Listener () {
			public void handleEvent(Event e) {
				cacheDir.setCapture(false);
			}
		});
		cacheDir.addListener(SWT.FocusIn, new Listener () {
			public void handleEvent(Event e) {
					if(isDialogOpen){
						isDialogOpen = false;
						cacheDirButton.setFocus();
					}
					else {
						isDialogOpen = true;
						cacheDirSelected();
					}
			}
		});
		cacheDir.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "cache",  //$NON-NLS-1$
							Messages.CacheDir_desc) );
			}
		});
		cacheDir.addMouseTrackListener(mouseExit);
		cacheDirButton = new Button(composite, SWT.PUSH);
		cacheDirButton.setText(Messages.Browse);
		cacheDirButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				cacheDirSelected();
			}
		});
		cacheDir.setText("cache"+File.separator);

		new Label(composite, SWT.NONE).setText(Messages.LogoPath+":"); //$NON-NLS-1$
		logoPath = new Text(composite, SWT.BORDER | SWT.SINGLE);
		gd = new GridData();
		gd.horizontalSpan = max-2;
		gd.horizontalAlignment = SWT.FILL;
		logoPath.setLayoutData(gd);
		logoPath.addListener(SWT.MouseDown, new Listener () {
			public void handleEvent(Event e) {
				logoPath.setCapture(false);
			}
		});
		logoPath.addListener(SWT.FocusIn, new Listener () {
			public void handleEvent(Event e) {
					if(isDialogOpen){
						isDialogOpen = false;
						logoButton.setFocus();
					}
					else {
						isDialogOpen = true;
						logoSelected();
					}
			}
		});
		logoPath.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "logo",  //$NON-NLS-1$
							Messages.LogoPath_desc) );
			}
		});
		logoPath.addMouseTrackListener(mouseExit);
		logoPath.setText("image"+File.separator+"titan.jpg");
		logoButton = new Button(composite, SWT.PUSH);
		logoButton.setText(Messages.Browse);
		logoButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				logoSelected();
			}
		});

		new Label(composite, SWT.NONE).setText(Messages.TimeZone+":"); //$NON-NLS-1$
		timeZoneCombo = new Combo (composite, SWT.READ_ONLY);
		//Get actual timeZones [in a asynchronous thread, to run separately]
		getShell().getDisplay().asyncExec( new Runnable() {  public void run() {
			String timeZoneIds[] = TimeZone.getAvailableIDs();
			String defaultTimeZoneId = TimeZone.getDefault().getID();
			for (int i = 0; i < timeZoneIds.length; i++){
				TimeZone tz = TimeZone.getTimeZone(timeZoneIds[i]);
				// Get the number of hours from GMT
				int rawOffset = tz.getRawOffset();
				int hour = rawOffset / (60*60*1000);
				int minute = Math.abs(rawOffset / (60*1000)) % 60;
				String sinal = hour > 0 ? "+" : hour == 0 ? " " : "-"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				String result = String.format("%s%02d:%02d - %s", sinal, Math.abs(hour), minute, timeZoneIds[i]); //$NON-NLS-1$

				timeZoneCombo.add(result);
				if(timeZoneIds[i].equals(defaultTimeZoneId))
					timeZoneCombo.select(i);
			}
		}});
		timeZoneCombo.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "timeZone", Messages.TimeZone_desc) ); //$NON-NLS-1$
			}
		});
		timeZoneCombo.addMouseTrackListener(mouseExit);
		gd = new GridData();
		gd.horizontalSpan = max-2;
		gd.horizontalAlignment = SWT.FILL;
		timeZoneCombo.setLayoutData(gd);

		new Label(composite, SWT.NONE);
		new Label(composite, SWT.NONE);
		new Label(composite, SWT.NONE).setText(Messages.NotInUse);
		new Label(composite, SWT.NONE);
		new Label(composite, SWT.NONE);
		new Label(composite, SWT.NONE).setText(Messages.Using);
		new Label(composite, SWT.NONE);

		Label label = new Label(composite, SWT.NONE);
		label.setText(Messages.Language+":"); //$NON-NLS-1$
		gd = new GridData();
		gd.verticalSpan = 2;
		label.setLayoutData(gd);

		notUsedLang = new List(composite, SWT.MULTI | SWT.BORDER | SWT.READ_ONLY  );
		notUsedLang.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "notUsedLang", Messages.NotUsing_desc) ); //$NON-NLS-1$
			}
		});
		notUsedLang.addMouseTrackListener(mouseExit);
		notUsedLang.removeAll();
		notUsedLang.add("en_US"); //$NON-NLS-1$
		notUsedLang.add("es_ES"); //$NON-NLS-1$
		gd = new GridData(140, 50);
		gd.verticalSpan = 2;
		gd.horizontalSpan = 2;
		gd.horizontalAlignment = SWT.FILL;
		notUsedLang.setLayoutData(gd);

		Button plusButton = new Button(composite, SWT.PUSH);
		plusButton.setText("+"); //$NON-NLS-1$
		plusButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				String[] selection = notUsedLang.getSelection();
				for (int i=0; i<selection.length; i++){
					notUsedLang.remove(selection[i]);
					usedLang.add(selection[i]);
				}
			}
		});

		usedLang = new List(composite, SWT.MULTI | SWT.BORDER | SWT.READ_ONLY  );
		usedLang.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "usedLang", Messages.Using_desc) ); //$NON-NLS-1$
			}
		});
		usedLang.addMouseTrackListener(mouseExit);
		usedLang.removeAll();
		usedLang.add("pt_BR"); //$NON-NLS-1$
		gd = new GridData(140, 50);
		gd.verticalSpan = 2;
		gd.horizontalAlignment = SWT.FILL;
		usedLang.setLayoutData(gd);

		Label label2 = new Label(composite, SWT.NONE);
		gd = new GridData();
		gd.verticalSpan = 2;
		label2.setLayoutData(gd);

		Button minusButton = new Button(composite, SWT.PUSH);
		minusButton.setText("-"); //$NON-NLS-1$
		minusButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				String[] selection = usedLang.getSelection();
				if(usedLang.getSelectionCount() < usedLang.getItemCount())
					for (int i=0; i<selection.length; i++){
						usedLang.remove(selection[i]);
						notUsedLang.add(selection[i]);
					}
				else
					MessageDialog.openError(getShell(), Messages.Error,Messages.AtLeast1Lang);
			}
		});

		section = new Button(composite, SWT.CHECK);
		section.setText(Messages.AllSections);
		section.setSelection(true);
		section.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "section", Messages.AllSections_desc) ); //$NON-NLS-1$
			}
		});
		section.addMouseTrackListener(mouseExit);

		chat = new Button(composite, SWT.CHECK);
		chat.setText(Messages.UseChat);
		chat.setSelection(false);
		chat.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "chat", Messages.UseChat_desc) ); //$NON-NLS-1$
			}
		});
		chat.addMouseTrackListener(mouseExit);

		debug = new Button(composite, SWT.CHECK);
		debug.setText(Messages.DebugMode);
		debug.setSelection(true);
		debug.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "debug", Messages.DebugMode_desc) ); //$NON-NLS-1$
			}
		});
		debug.addMouseTrackListener(mouseExit);

		new Label(composite, SWT.NONE);
		firefox = new Button(composite, SWT.CHECK);
		firefox.setText(Messages.OnlyFirefox);
		firefox.setSelection(false);
		firefox.addListener(SWT.MouseEnter, new Listener () {
			public void handleEvent(Event e) {
			    applyStatus(new Status(IStatus.INFO, "firefox", Messages.OnlyFirefox_desc) ); //$NON-NLS-1$
			}
		});
		firefox.addMouseTrackListener(mouseExit);
	}

	/**
	 * Method to suggest a project name to this page
	 * @param suggestedName - the suggested project name
	 */
	void suggestName(String suggestedName){
		active = false;
		name.setText(suggestedName);
		url.setText("http://localhost/"+suggestedName);
	}

	/**
	 * {@inheritDoc}
	 */
	public boolean canFlipToNextPage() {
		if (pageStatus.getSeverity() != IStatus.ERROR && !name.getText().isEmpty() && !description.getText().isEmpty() //$NON-NLS-1$ //$NON-NLS-2$
			&& !email.getText().isEmpty() && !url.getText().isEmpty() && url.getText().compareTo("http://") != 0 //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
			&& !loginUrl.getText().isEmpty() && !cacheDir.getText().isEmpty() && !logoPath.getText().isEmpty()) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
			return true;
		return false;
	}

	/**
	 * This function is called when cache directory was selected.
	 * It validates the informed cache path
	 */
	private void cacheDirSelected() {
		String fn = SWTUtils.openFolderDialog(getShell());
		if (fn != null) {
			cacheDir.setText(fn);
			try {
				if(!FileUtils.isEmptyFolder(fn))
				    applyStatus(new Status(IStatus.WARNING, "cacheDir", //$NON-NLS-1$
				    		Messages.CacheFolderNEmpty+Messages.ContentWillBeReplaced) );
			} catch (Exception e) {
				MessageDialog.openError(getShell(), Messages.Error, e.getMessage());
			}
		}
		updateButtons();
	}

	/**
	 * This function is called when logo path was selected.
	 * It validates the informed logo
	 */
	private void logoSelected() {
		String fn = SWTUtils.openFileDialog(getShell(), FILTER_NAMES, FILTER_EXTS);
		if (fn != null)
			try {
	        	ImageData imageData = new ImageData(fn);
	            if (imageData.height > 56)
					MessageDialog.openError(getShell(), Messages.Error, Messages.Height56pxLimit);
	            else
	            	logoPath.setText(fn);
			} catch (Exception e) {
				MessageDialog.openError(getShell(), Messages.Error, e.getMessage());
			}
		updateButtons();
	}

	/**
	 * {@inheritDoc}
	 */
	protected void applyStatus(IStatus new_status) {
		if(new_status.getSeverity() != IStatus.INFO){
			String plugin = new_status.getPlugin();
			if(plugin == "name") //$NON-NLS-1$
				nameStatus = new_status;
			else if(plugin == "url") //$NON-NLS-1$
				urlStatus = new_status;
			else if(plugin == "email") //$NON-NLS-1$
				emailStatus = new_status;
			else if(plugin == "loginUrl") //$NON-NLS-1$
				loginUrlStatus = new_status;
			else if(plugin == "cacheDir") //$NON-NLS-1$
				cacheDirStatus = new_status;
			else
				logoPathStatus = new_status;
		}
		applyPageStatus(new_status);
	}

	/**
	 * {@inheritDoc}
	 */
	protected IStatus greaterStatus() {
		IStatus greater = nameStatus;
		if(greater.getSeverity() < urlStatus.getSeverity())
			greater = urlStatus;
		if(greater.getSeverity() < emailStatus.getSeverity())
			greater = emailStatus;
		if(greater.getSeverity() < loginUrlStatus.getSeverity())
			greater = loginUrlStatus;
		if(greater.getSeverity() < cacheDirStatus.getSeverity())
			greater = cacheDirStatus;
		if(greater.getSeverity() < logoPathStatus.getSeverity())
			greater = logoPathStatus;
		return greater;
	}
}